home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume3 / pcmail / part02 < prev    next >
Encoding:
Internet Message Format  |  1989-02-03  |  57.1 KB

  1. Path: xanth!mcnc!uvaarpa!umd5!purdue!decwrl!decvax!mandrill!hal!ncoast!allbery
  2. From: wswietse@eutrc3.UUCP (Wietse Venema)
  3. Newsgroups: comp.sources.misc
  4. Subject: v03i003: uucp mail for pc's (2 of 8)
  5. Message-ID: <211@eutrc3.UUCP>
  6. Date: 20 Apr 88 16:42:31 GMT
  7. Sender: allbery@ncoast.UUCP
  8. Reply-To: wswietse@eutrc3.UUCP (Wietse Venema)
  9. Organization: Tech. Univ. Eindhoven, Neth.
  10. Lines: 1976
  11. Approved: allbery@ncoast.UUCP
  12.  
  13. comp.sources.misc: Volume 3, Issue 3
  14. Submitted-By: "Wietse Venema" <wswietse@eutrc3.UUCP>
  15. Archive-Name: pcmail/Part2
  16.  
  17. #! /bin/sh
  18. # This is a shell archive.  Remove anything before this line, then unpack
  19. # it by saving it into a file and typing "sh file".  To overwrite existing
  20. # files, type "sh file -c".  You can also feed this as standard input via
  21. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  22. # will see the following message at the end:
  23. #        "End of archive 2 (of 8)."
  24. # Contents:  desk.c errdisp.c gtrans.c kbdinp.c kio.c window.c
  25. # Wrapped by wietse@eutwc1 on Wed Apr 20 16:45:02 1988
  26. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  27. if test -f desk.c -a "${1}" != "-c" ; then 
  28.   echo shar: Will not over-write existing file \"desk.c\"
  29. else
  30. echo shar: Extracting \"desk.c\" \(7613 characters\)
  31. sed "s/^X//" >desk.c <<'END_OF_desk.c'
  32. X/*++
  33. X/* NAME
  34. X/*    desk 3
  35. X/* SUMMARY
  36. X/*    mail box display
  37. X/* PROJECT
  38. X/*    pc-mail
  39. X/* PACKAGE
  40. X/*    mailsh
  41. X/* SYNOPSIS
  42. X/*    #include "mailsh.h"
  43. X/*
  44. X/*    void desk()
  45. X/*
  46. X/*    int junk_desk()
  47. X/*
  48. X/*    char message[];
  49. X/*    char comment[];
  50. X/* DESCRIPTION
  51. X/*      Most functions in this module are invoked by the keyboard interpreter
  52. X/*      and are responsible for the mail box view of message summary lines.
  53. X/*
  54. X/*    desk() is the main entry point. It presents the user with a sorted
  55. X/*    display of message files and a list of commands to choose from.
  56. X/*
  57. X/*    patience() informs the user that an operation may take some time.
  58. X/*    It puts the 'one moment please..'  in the middle screen window.
  59. X/*    As a side effect, it sets the current pager file to none.
  60. X/*
  61. X/*    junk_desk() should be invoked when the number of files in the mail box
  62. X/*    may have changed. Always returns a zero value. This function
  63. X/*    should be called when a message is added to, or deleted from, the
  64. X/*    spool directory.
  65. X/*
  66. X/*    The strings "message" and "comment" hold path names of the currently
  67. X/*    selected message file, and its associated metafile (with message
  68. X/*    destination, origin or comments). These names are used by functions 
  69. X/*    that read, delete or otherwise manipulate message files.
  70. X/* FILES
  71. X/*      mail header files in the spool directory
  72. X/* SEE ALSO
  73. X/*      pager(3), pager(5), kbdinp(3)
  74. X/* DIAGNOSTICS
  75. X/*      If a selected mail message could not be found an error message
  76. X/*      is displayed instead.
  77. X/* BUGS
  78. X/*      Since a message can be accessed only if its metafile exists,
  79. X/*    a message is "lost" when for some reason the metafile is
  80. X/*    not available.
  81. X/* AUTHOR(S)
  82. X/*      W.Z. Venema
  83. X/*      Eindhoven University of Technology
  84. X/*      Department of Mathematics and Computer Science
  85. X/*      Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  86. X/* CREATION DATE
  87. X/*    Tue May 12 15:35:20 GMT+1:00 1987
  88. X/* LAST MODIFICATION
  89. X/*    Mon Apr  4 23:37:48 MET 1988
  90. X/* VERSION/RELEASE
  91. X/*    1.3
  92. X/*--*/
  93. X
  94. X#include <errno.h>
  95. X#include <sys/types.h>
  96. X#include <sys/stat.h>
  97. X#include <time.h>
  98. X#include "defs.h"
  99. X#include "mailsh.h"
  100. X#include "path.h"
  101. X#include "dir.h"
  102. X#include "pager.h"
  103. X#include "screen.h"
  104. X#include "status.h"
  105. X#include "window.h"
  106. X
  107. Xextern struct tm *localtime();              /* std C library */
  108. X
  109. Xhidden void make_desk();            /* forward declarations */
  110. Xhidden int pick_desk();
  111. Xhidden int show_desk();
  112. Xhidden void add_desk();
  113. X
  114. Xhidden File *deskfile = 0;            /* mail box pager file */
  115. Xpublic char message[BUFSIZ];            /* path to message file */
  116. Xpublic char comment[BUFSIZ];            /* path to comment file */
  117. Xhidden int msgid;                /* message id */
  118. X
  119. X/* description of the mail summary lines in the main screen */
  120. X
  121. Xtypedef struct {
  122. X    char *category;        /* work, incoming, outgoing, ... */
  123. X    char *comtype;        /* from, to, ... */
  124. X    char *msgpfx;        /* message-file prefix */
  125. X    char *compfx;        /* meta-file prefix */
  126. X    int (*access)();        /* message access function */
  127. X} Summary;
  128. X
  129. Xhidden char makeletter[] = "(create a new message)";
  130. X
  131. Xhidden Summary summary[] = {
  132. X    "new",    makeletter,    EDTPFX,    COMPFX,    mail,    /* new mail */
  133. X    "Work",    "Name:",    EDTPFX,    COMPFX,    mail,    /* in preparation */
  134. X    "Out",    "To:",        MSGPFX,    XQTPFX,    mbox,    /* queued */
  135. X    "New",    "From:",    NEWPFX, HDRPFX, mbox,    /* new mail */
  136. X    "In",    "From:",    NEWPFX,    OLDPFX,    mbox,    /* old mail */
  137. X    0,                            /* terminator */
  138. X};
  139. X
  140. Xhidden char dispfmt[] = "%-4s %5d  %s  %-5s %s";
  141. Xhidden char scanfmt[] = "%s %d";
  142. X
  143. X/* desk - main entry point for message manipulations */
  144. X
  145. Xpublic void desk()
  146. X{
  147. X    static Screen screen[] = {
  148. X    'C',    "Close",    0,      "Terminate the program",
  149. X    'F',    "File",        file,   "Mail a copy of an ordinary file",
  150. X    'N',    "Network",    call,   "Exchange mail with the network",
  151. X    'S',    "Setup",        setup,  "Set communications parameters",
  152. X    'A',    "Alias",    alias,    "Display the alias data base",
  153. X    'P',    "Print",    print,    "Print message-summary display",
  154. X    PGUP,    PgUp,        pu_pager,pageup,
  155. X    PGDN,    PgDn,        pd_pager,pagedn,
  156. X    UP,    "Up",           up_pager,csrup,
  157. X    DOWN,    "Down",         dn_pager,csrdn,
  158. X    ENTER,    "Enter",        pick_desk,"Select message at cursor",
  159. X    0,    0,        show_desk,
  160. X    "Select a message with cursor keys and press ENTER\n\
  161. Xor select one of the commands in the top line."
  162. X    };
  163. X
  164. X    kbdinp(screen);                /* and there they go... */
  165. X}
  166. X
  167. X/* show_desk - create or refresh a display of the mail box */
  168. X
  169. Xhidden int show_desk()
  170. X{
  171. X    if (deskfile == 0) {            /* no mail box pager file */
  172. X    patience();                /* one moment please... */
  173. X    make_desk(deskfile = open_pager());    /* build mail box display */
  174. X    } else {                    /* pager file exists */
  175. X    set_pager(deskfile);            /* select pager file */
  176. X    }
  177. X    ds_pager();                    /* display it */
  178. X    return(0);                    /* screen is ok */
  179. X}
  180. X
  181. X/* make_desk - build pager file of summary lines */
  182. X
  183. Xhidden void make_desk(pp)
  184. XFile *pp;
  185. X{
  186. X    register Summary *s = summary;
  187. X
  188. X    /* display the "empty sheet of paper" line first */
  189. X
  190. X    app_pager(pp,strcons(dispfmt,s->category,0,s->comtype,"",""));
  191. X
  192. X    /* display summary lines for "New", "Work" and "Old" messages */
  193. X
  194. X    for (s = summary+1; s->category; s++)
  195. X    add_desk(pp,s);
  196. X
  197. X    /* sort summary lines in reverser order */
  198. X
  199. X    sort_pager(pp,BACK_SORT);            /* sort mail box display */
  200. X}
  201. X
  202. X/* pick_desk - user selected a message */
  203. X
  204. Xhidden int pick_desk()
  205. X{
  206. X    char type[BUFSIZ];
  207. X    register Summary *s;
  208. X
  209. X    /* 
  210. X    * Read message type (in, out, work etc) and sequence number from 
  211. X    * summary line in the mail box display. Then call the appropriate
  212. X    * function to access that message.
  213. X    */
  214. X
  215. X    type[0] = msgid = 0;             /* initialize */
  216. X    scan_pager(deskfile,scanfmt,type,&msgid);    /* which message chosen? */
  217. X    if (msgid == 0)                /* new message? */
  218. X    msgid = newseqno();            /* choose new message id */
  219. X
  220. X    for (s = summary; s->category; s++) {    /* try to recognize the */
  221. X    if (strcmp(s->category,type) == 0) {    /* message type */
  222. X        strcpy(message,mesg_file(s->msgpfx,msgid)); /* msg file name */
  223. X        strcpy(comment,meta_file(s->compfx,msgid)); /* metafile name */
  224. X        return(CALL(s->access)(type,msgid));/* display the message */
  225. X    }
  226. X    }
  227. X    beep();                    /* unrecognized message type */
  228. X    return(0);                    /* nothing happened */
  229. X}
  230. X
  231. X/* junk_desk - force rebuilding of mail box display */
  232. X
  233. Xpublic int junk_desk()
  234. X{
  235. X    if (deskfile) {
  236. X    close_pager(deskfile);            /* delete pager file */
  237. X    deskfile = 0;                /* say it's gone */
  238. X    }
  239. X    return(0);                    /* in case one wants it */
  240. X}
  241. X
  242. X/*
  243. X* add_desk() is invoked to build the main mail box menu screen.
  244. X* It searches the spool directory for metafiles of the
  245. X* specified type and writes their contents to the specified
  246. X* pager file, together with message type, message id and
  247. X* creation time of the corresponding message file.
  248. X*/
  249. X
  250. X/* add_desk - append summaries with type in s to pager file in pp */
  251. X
  252. Xhidden void add_desk(pp,s)
  253. XFile *pp;
  254. Xregister Summary *s;
  255. X{
  256. X    int prelen = strlen(s->msgpfx);        /* length of prefix */
  257. X    FILE *fp;                    /* used to read summaries */
  258. X    char *f;                    /* message file name */
  259. X    int dd;                    /* dir search id */
  260. X    int msgno;                    /* message number */
  261. X    struct stat st;                /* file information */
  262. X
  263. X    for (dd = opendir(maildir); f = readdir(dd); /* void */) {
  264. X    if (!strncmp(s->msgpfx,f,prelen) && sscanf(f+prelen,"%d",&msgno)
  265. X        && stat(mesg_file(s->msgpfx,msgno),&st) == 0
  266. X        && (fp = fopen(meta_file(s->compfx,msgno),"r"))) {
  267. X        char meta[BUFSIZ];            /* meta-file info */
  268. X        fgets(meta,BUFSIZ,fp);        /* read meta info */
  269. X        meta[strlen(meta)-1] = '\0';    /* chop off newline char */
  270. X        app_pager(pp,strcons(dispfmt,s->category,msgno,
  271. X        tstamp(&st.st_mtime),s->comtype,meta));
  272. X        fclose(fp);
  273. X    }
  274. X    }
  275. X    closedir(dd);                /* terminate file search */
  276. X}
  277. END_OF_desk.c
  278. if test 7613 -ne `wc -c <desk.c`; then
  279.     echo shar: \"desk.c\" unpacked with wrong size!
  280. fi
  281. # end of overwriting check
  282. fi
  283. if test -f errdisp.c -a "${1}" != "-c" ; then 
  284.   echo shar: Will not over-write existing file \"errdisp.c\"
  285. else
  286. echo shar: Extracting \"errdisp.c\" \(7706 characters\)
  287. sed "s/^X//" >errdisp.c <<'END_OF_errdisp.c'
  288. X/*++
  289. X/* NAME
  290. X/*      errdisp 3
  291. X/* SUMMARY
  292. X/*      produce an error message display
  293. X/* PROJECT
  294. X/*      pc-mail
  295. X/* PACKAGE
  296. X/*      mailsh
  297. X/* SYNOPSIS
  298. X/*      int errdisp(errcode);
  299. X/*      int errcode;
  300. X/* DESCRIPTION
  301. X/*      errdisp() produces an error display in the middle screen
  302. X/*      window. The error code must be one defined in status.h.
  303. X/*    Otherwise, an "unknown error" message is displayed.
  304. X/*    errdisp() gives the user a chance to read it, before resuming
  305. X/*      the program. errdisp() returns its argument, or the
  306. X/*    value E_UNKNOWN if an unknown error code was specified.
  307. X/* FUNCTIONS AND MACROS
  308. X/*      kbdinp(), open_pager(), app_pager(), ds_pager(), close_pager()
  309. X/* BUGS
  310. X/*      Cannot force the user to really stop. It just recommends
  311. X/*      to do so.
  312. X/* AUTHOR(S)
  313. X/*      W.Z. Venema
  314. X/*      Eindhoven University of Technology
  315. X/*      Department of Mathematics and Computer Science
  316. X/*      Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  317. X/* CREATION DATE
  318. X/*      Thu Apr  9 21:19:05 GMT+1:00 1987
  319. X/* LAST MODIFICATION
  320. X/*    Mon Apr  4 23:39:44 MET 1988
  321. X/* VERSION/RELEASE
  322. X/*    1.3
  323. X/*--*/
  324. X
  325. X#include "defs.h"
  326. X#include "screen.h"
  327. X#include "pager.h"
  328. X#include "status.h"
  329. X#include "window.h"
  330. X
  331. X/* forward declarations */
  332. X
  333. Xhidden int ds_error();
  334. X
  335. X/* A list of error mesages */
  336. X
  337. X/* when the spool directory is not found */
  338. X
  339. Xhidden char *e_nospool[] = {
  340. X    "",
  341. X    "The mail program cannot access essential data files.",
  342. X    "",
  343. X    "Please check whether the spool directory is present",
  344. X    "and whether the environment variable MAILDIR has been",
  345. X    "set correctly.",
  346. X    0,
  347. X};
  348. X
  349. X/* when we cannot open as many files as we need */
  350. X
  351. Xhidden char *e_fileno[] = {
  352. X    "",
  353. X#ifdef  MSDOS
  354. X    "Check your CONFIG.SYS file. It should have a line",
  355. X    "stating (for example)",
  356. X    "    FILES = 20 .",
  357. X    "While you're at it, also make sure that file also",
  358. X    "has a line (for example)",
  359. X    "    DEVICE = ANSI.SYS .",
  360. X    "If your system does not have such a file create",
  361. X    "one with an editor and place the file in the root",
  362. X    "directory.",
  363. X    "Reboot after making the changes and try again.",
  364. X#endif
  365. X#ifdef  unix
  366. X    "Your UNIX is crippled (not enough file descriptors",
  367. X    "per process). Rebuild the system or buy a better one.",
  368. X#endif
  369. X    0,
  370. X};
  371. X
  372. X/* when a program is not found */
  373. X
  374. Xhidden char *e_noprog[] = {
  375. X    "",
  376. X    "The mail program cannot execute an essential program file.",
  377. X    "",
  378. X    "Please make sure that the environment variable PATH has",
  379. X    "been set to include the directories with the SMAIL, RMAIL,",
  380. X    "CICO and EDITOR programs.",
  381. X    "Also, make sure that the environment variable EDITOR has",
  382. X    "been set to the editor of your preference, and that the",
  383. X    "machine has enough free memory",
  384. X    0,
  385. X};
  386. X
  387. X/* when a read error ocurred, or a file could not be opened */
  388. X
  389. Xhidden char *e_readerr[] = {
  390. X    "",
  391. X    "The mail program cannot read a data file.",
  392. X    "",
  393. X    "Please check your disk. This may be a serious problem.",
  394. X    0,
  395. X};
  396. X
  397. X/* when a write error occurred */
  398. X
  399. Xhidden char *e_writerr[] = {
  400. X    "",
  401. X    "The mail program cannot write a data file.",
  402. X    "",
  403. X    "Please make sure that the disk is not write protected",
  404. X    "and that there is sufficient free space.",
  405. X    0,
  406. X};
  407. X
  408. X/* when the program is confused */
  409. X
  410. Xhidden char *e_confused[] = {
  411. X    "",
  412. X    "The mail program has detected a serious internal problem.",
  413. X    "",
  414. X    "You are requested to leave the mail system as it is and",
  415. X    "call an expert.",
  416. X    0,
  417. X};
  418. X
  419. X/* an unknown error (perhaps the editor returned a nonzero status) */
  420. X
  421. Xhidden char *e_unknown[] = {
  422. X    "",
  423. X    "The mail program has detected a unknown error. This may",
  424. X    "not be a serious problem.",
  425. X    0,
  426. X};
  427. X
  428. X/* when the UNIX host does not ask for login/password */
  429. X
  430. Xhidden char *e_noline[] = {
  431. X    "",
  432. X    "The mail program is not able to exchange mail with the",
  433. X    "network.",
  434. X    "",
  435. X    "Please check the password, or try again later.",
  436. X    0,
  437. X};
  438. X
  439. X/* when the UNIX host does not send initial protocol messages */
  440. X
  441. Xhidden char *e_noresp[] = {
  442. X    "",
  443. X    "The mail program is not able to exchange mail with the",
  444. X    "network. Probably the password was incorrect.",
  445. X    0,
  446. X};
  447. X
  448. X/* when the UNIX host does not want to talk to us */
  449. X
  450. Xhidden char *e_reject[] = {
  451. X    "",
  452. X    "The mail program is not able to exchange mail with the",
  453. X    "network. Please contact the system administrator who is",
  454. X    "responsible for the nearest UNIX system.",
  455. X    0,
  456. X};
  457. X
  458. X/* when the link is lost (timeout,...) */
  459. X
  460. Xhidden char *e_lost[] = {
  461. X    "",
  462. X    "The mail program has lost contact with the network.",
  463. X    "",
  464. X    "We suggest that you try again at a later time.",
  465. X    0,
  466. X};
  467. X
  468. X/* the resources are exhausted */
  469. X
  470. Xhidden char *e_sysfail[] = {
  471. X    "",
  472. X    "The mail program cannot proceed due to the fact",
  473. X    "that the computer system is overloaded.",
  474. X    "",
  475. X    "Consult your local systems manager.",
  476. X    0,
  477. X};
  478. X
  479. X/* bad setup parameter */
  480. X
  481. Xhidden char *e_badsetup[] = {
  482. X    "",
  483. X    "The mail program cannot communicate with the network",
  484. X    "due to missing or invalid data in the setup.",
  485. X    "",
  486. X    "Check the Setup command in the main menu.",
  487. X    0,
  488. X};
  489. X
  490. X/* when a file could not be removed */
  491. X
  492. Xhidden char *e_unlink[] = {
  493. X    "",
  494. X    "The mail program cannot remove a data file.",
  495. X    "",
  496. X    "Please make sure that your disk is not write protected",
  497. X    0,
  498. X};
  499. X
  500. X/* when a file could not be printed */
  501. X
  502. Xhidden char *e_printerr[] = {
  503. X    "",
  504. X    "The mail programm cannot write to the printer",
  505. X    "",
  506. X    "Please check your default printer device",
  507. X    0,
  508. X};
  509. X
  510. Xhidden char *e_nouser[] = {
  511. X    "",
  512. X    "An unknown local user name was specified",
  513. X    "",
  514. X    "Please check the list of user names",
  515. X    0,
  516. X};
  517. X
  518. Xhidden char *e_ovalias[] = {
  519. X    "",
  520. X    "There probably is an error in your alias data base,",
  521. X    "such that an alias is defined in terms of itself.",
  522. X    "",
  523. X    "Please check your alias data base, and then try to",
  524. X    "send this message again.",
  525. X    0,
  526. X};
  527. X
  528. X/* The folowing data structure links an error code to an error message */
  529. X
  530. Xtypedef struct {
  531. X    short code;                /* error return value */
  532. X    char **msg;                /* associated message */
  533. X} msgmap;
  534. X
  535. Xhidden msgmap errmap[] = {        /* lookup table for error codes */
  536. X    E_UNKNOWN,    e_unknown,        /* don't remove this one! */
  537. X    E_SYSFAIL,    e_sysfail,
  538. X    E_NOPROG,    e_noprog,        /* and error messages */
  539. X    E_NOSPOOL,    e_nospool,
  540. X    E_READERR,    e_readerr,
  541. X    E_WRITERR,    e_writerr,
  542. X    E_CONFUSED,    e_confused,
  543. X    E_FILENO,    e_fileno,
  544. X    E_NOLINE,    e_noline,
  545. X    E_NORESP,    e_noresp,
  546. X    E_REJECT,    e_reject,
  547. X    E_LOST,    e_lost,
  548. X    E_BADSETUP,    e_badsetup,
  549. X    E_UNLINK,    e_unlink,
  550. X    E_PRINTERR,    e_printerr,
  551. X    E_NOUSER,    e_nouser,
  552. X    E_OVALIAS,    e_ovalias,
  553. X    0,        0,            /* terminator */
  554. X};
  555. X
  556. X/* errdisp - set up error pager file, return error code */
  557. X
  558. Xpublic int errdisp(code)
  559. Xint code;
  560. X{
  561. X    static Screen screen[] = {
  562. X    ENTER,    "Enter",        0,      "Resume the mail program",
  563. X    0,    0,              ds_error,"Press ENTER to continue",
  564. X    };
  565. X    register msgmap *mp;
  566. X
  567. X    /* linear table search; this code is not used heavily */
  568. X
  569. X    for (mp = errmap; mp->code && mp->code != code; mp++)
  570. X    /* void */ ;                /* look it up in table */
  571. X    if (mp->code == 0) {
  572. X    return(errdisp(E_UNKNOWN));        /* unknown error code */
  573. X    } else {
  574. X    File *pp = open_pager();        /* open pager file */
  575. X    beep();                    /* red alert! red alert! */
  576. X    mesg_pager(pp,mp->msg);            /* copy to pager file */
  577. X    kbdinp(screen);                /* give a chance to read it */
  578. X    close_pager(pp);            /* forget screen display */
  579. X    return(code);                /* return error code */
  580. X    }
  581. X}
  582. X
  583. X/* ds_error - display error window */
  584. X
  585. Xhidden int ds_error()
  586. X{
  587. X    ds_pager();                    /* use "current" pager file */
  588. X    return(0);                    /* say screen up-to-date */
  589. X}
  590. END_OF_errdisp.c
  591. if test 7706 -ne `wc -c <errdisp.c`; then
  592.     echo shar: \"errdisp.c\" unpacked with wrong size!
  593. fi
  594. # end of overwriting check
  595. fi
  596. if test -f gtrans.c -a "${1}" != "-c" ; then 
  597.   echo shar: Will not over-write existing file \"gtrans.c\"
  598. else
  599. echo shar: Extracting \"gtrans.c\" \(10263 characters\)
  600. sed "s/^X//" >gtrans.c <<'END_OF_gtrans.c'
  601. X/*++
  602. X/* NAME
  603. X/*    gtrans 3
  604. X/* SUMMARY
  605. X/*    g protocol strategy functions
  606. X/* PROJECT
  607. X/*    pc-mail
  608. X/* PACKAGE
  609. X/*    cico
  610. X/* SYNOPSIS
  611. X/*    #include "gp.h"
  612. X/*
  613. X/*    int ginit(fd)
  614. X/*    int fd;
  615. X/*
  616. X/*    Packet *galloc()
  617. X/*
  618. X/*    void gsproto(fd,pk)
  619. X/*    int fd;
  620. X/*    Packet *pk;
  621. X/*
  622. X/*    Packet *grproto(fd)
  623. X/*    int fd;
  624. X/*
  625. X/*    void gfree(pk)
  626. X/*    Packet *pk;
  627. X/*
  628. X/*    int gfinit(fd)
  629. X/*    int fd;
  630. X/* DESCRIPTION
  631. X/*    ginit() exchanges the initial g protocol messages and allocates
  632. X/*    memory for packet buffers.
  633. X/*
  634. X/*    galloc() returns a pointer to a free packet, after filling
  635. X/*    in its k and len fields. This packet is supposed to be filled
  636. X/*    with data, and to be subsequently queued with gsproto().
  637. X/*
  638. X/*    grproto() extracts the next packet from the input queue.
  639. X/*    The packet should be returned to the free pool with gfree().
  640. X/*
  641. X/*    gfinit() sends protocol termination messages until it receives one
  642. X/*    or until it gets bored.
  643. X/* FUNCTIONS AND MACROS
  644. X/*    gsctrl(), gsdata(), grpack(), gfail()
  645. X/* DIAGNOSTICS
  646. X/*    ginit(), gfinit() return a nonzero value if there was a problem.
  647. X/*
  648. X/*    The other functions return through a call of gfail() in case of
  649. X/*    unrecoverable problems.
  650. X/* BUGS
  651. X/*    Window size is equal to one. This implies that the program 
  652. X/*    only sends new data when the previous packet was acknowledged.
  653. X/*    However, only the functions in *this* module need to be adapted 
  654. X/*    to accomodate larger transmission window sizes.
  655. X/* AUTHOR(S)
  656. X/*    W.Z. Venema
  657. X/*    Eindhoven University of Technology
  658. X/*    Department of Mathematics and Computer Science
  659. X/*    Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  660. X/* CREATION DATE
  661. X/*    Sun Apr 19 17:30:08 GMT+1:00 1987
  662. X/* LAST MODIFICATION
  663. X/*    Mon Apr  4 23:41:52 MET 1988
  664. X/* VERSION/RELEASE
  665. X/*    1.3
  666. X/*--*/
  667. X
  668. X#include "gp.h"
  669. X
  670. X/*
  671. X* "The protocol is defined in terms of message transmissions of 8-bit bytes."
  672. X* "Each message includes one control byte plus a data segment of zero or more"
  673. X* "information bytes. The allowed data segment sizes range between 32 and"
  674. X* "4096 as determined by the formula 32*2^k where k is a 3-bit number."
  675. X*/
  676. X
  677. Xint seglen[] = {             /* data segment sizes */
  678. X    1,32,64,128,256,512,1024,2048,4096,
  679. X};
  680. X
  681. Xstatic int sndseg;            /* data segment k-value they want */
  682. Xstatic int sndlen;            /* data segment length they want */
  683. Xstatic int sndwin;            /* transmission window size they want */
  684. X
  685. X#define ourseg    2            /* data segment k-value we want */
  686. X#define ourlen    64            /* data segment length we want */
  687. X#define ourwin    1            /* transmission window size we want */
  688. X
  689. Xstatic Packet *inpk = 0;        /* receive packet "pool" */
  690. Xstatic Packet *outpk = 0;        /* send packet "pool" */
  691. X
  692. Xstatic int rval = 0;            /* our R value */
  693. Xstatic int sval = 1;            /* our S value */
  694. X
  695. X/*
  696. X* "Initial synchronization is accomplished with two 3-way handshakes:"
  697. X* "two each of INITA/INITB/INITC. Each sender transmits INITA messages"
  698. X* "repeatedly. When an INITA message is received, INITB is sent in return."
  699. X* "When an INITB message is received *and* an INITB message has been sent,"
  700. X* "an INITC message is sent. The INITA and INITB messages carry with them"
  701. X* "the packet and window size that each receiver wants to use, and the"
  702. X* "senders are supposed to comply. When a receiver has seen all three INIT"
  703. X* "messages, the channel is considered to be open. (...) the INIT messages"
  704. X* "are ignored elsewhere. (...)"
  705. X* "After initial synchronization each receiver sets a modulo-8"
  706. X* "incrementing counter R to 0; each sender sets a similar counter S to 1."
  707. X* "The value of R is always the number of the most recent correctly received"
  708. X* "packet. The value of S is always the first sequence number in the output"
  709. X* "window."
  710. X*
  711. X* Since INIT messages are ignored once the channel has been opened, we
  712. X* set the initial values of R and S at compile time.
  713. X*/
  714. X
  715. X/* ginit - g-protocol start-up */
  716. X
  717. Xint ginit(fd)
  718. Xint fd;
  719. X{
  720. X    register int state = 0;
  721. X    register int next = 0;
  722. X    int count = 0;
  723. X
  724. X    /* set up receive packet buffers */
  725. X
  726. X    if ((inpk = (Packet *) malloc((unsigned)sizeof(Packet)+ourlen)) == 0) {
  727. X    DEBUG(7,"gopen: malloc failed\n","");
  728. X    return(FAIL);
  729. X    }
  730. X
  731. X    /* 
  732. X    * Very simple automaton for initial message exchanges.
  733. X    * We send a packet, receive a packet and so on. The
  734. X    * automaton terminates when it reaches its accepting state,
  735. X    * when a time-out error occurs, or when it seems to get
  736. X    * stuck in one state.
  737. X    */
  738. X
  739. X    while (state != INITC) {
  740. X
  741. X    /* select action to be done in this state */
  742. X
  743. X    switch (state) {
  744. X    case 0:                    /* initial state */
  745. X        gsctrl(fd,INITA|IFLD(ourwin));    /* send INITA message */
  746. X        break;
  747. X    case INITA:                /* we received INITA */
  748. X        gsctrl(fd,INITB|IFLD(ourseg-1));    /* send INITB in response */
  749. X        break;
  750. X    case INITB:                /* we received INITB */
  751. X        gsctrl(fd,INITC|IFLD(ourwin));    /* assume we sent INITB */
  752. X        break;
  753. X    }
  754. X
  755. X    /*
  756. X    * Transition part of the automaton. Receive a packet and process
  757. X    * its contents. Depending on the packet and the current state
  758. X    * select a new state. Stay in the current state when a corrupted 
  759. X    * packet is received or when we receive an unexpected packet.
  760. X    * If no packet is received assume we have lost contact and terminate.
  761. X    */
  762. X
  763. X    switch (next = grpack(fd,inpk)) {    /* see what we get */
  764. X    case INITA:
  765. X        sndwin = IVAL(inpk->c);        /* transmission window size */
  766. X        state = next;
  767. X        break;
  768. X    case INITB:
  769. X        sndseg = IVAL(inpk->c)+1;        /* send-segment type */
  770. X        sndlen = seglen[sndseg];        /* send-segment length */
  771. X        state = (state == INITA ? next : state);
  772. X        break;
  773. X    case INITC:
  774. X        state = (state == INITB ? next : state);
  775. X        break;
  776. X    case FAIL:                /* corrupted message received */
  777. X        break;
  778. X    case TIME:                /* no message received */
  779. X        return(FAIL);
  780. X    }
  781. X
  782. X    /* check we don't stay in the same state forever */
  783. X
  784. X    if (state == next) {
  785. X        count = 0;
  786. X    } else if (count++ > MAXTRY) {
  787. X        return(FAIL);
  788. X    }
  789. X    }
  790. X
  791. X    /* set up transmission buffer "pool" */
  792. X
  793. X    if ((outpk = (Packet *) malloc((unsigned)sizeof(Packet)+sndlen)) == 0) {
  794. X    DEBUG(7,"gopen: malloc failed\n","");
  795. X    return(FAIL);
  796. X    }
  797. X    return(0);
  798. X}
  799. X
  800. X/*
  801. X* The current version used a window size of 1, i.e. no further data
  802. X* transmissions until the last transmitted data have been acknowledged.
  803. X* The following routines anticipate on future versions with a real pool of
  804. X* transmit and receive buffers.
  805. X*/
  806. X
  807. X/* galloc - allocate send packet, fill in size info */
  808. X
  809. XPacket *galloc()
  810. X{
  811. X    register Packet *pk = outpk;
  812. X
  813. X    pk->k = sndseg;                /* data segment type */
  814. X    pk->len = sndlen;                /* data segment size */
  815. X    return(pk);
  816. X}
  817. X
  818. X/* gfree - release receive packet */
  819. X
  820. Xvoid gfree(pk)
  821. Xregister Packet *pk;
  822. X{
  823. X    /* this function intentionally left blank */
  824. X}
  825. X
  826. X/*
  827. X* The central part of the protocol is in the routines gsproto() and
  828. X* grproto(). These are the functions that negotiate with the other
  829. X* host about what data to (re)transmit and to (n)ack.
  830. X* Major changes are to be expected here when larger transmission
  831. X* window sizes are to be supported.
  832. X*/
  833. X
  834. X/* gsproto - queue one packet for transmission */
  835. X
  836. Xvoid gsproto(fd,pk)
  837. Xint fd;
  838. XPacket *pk;
  839. X{
  840. X    int numtry = 0;                /* retry count */
  841. X
  842. X    gsdata(fd,pk,SFLD(sval)|RFLD(rval));    /* send data packet */
  843. X
  844. X    inpk->k = ourseg;                /* "allocate" receive packet */
  845. X    inpk->len = ourlen;
  846. X
  847. X    while (numtry < MAXTRY) {
  848. X    switch (grpack(fd,inpk)) {        /* what is the reply */
  849. X    case SHORT:                /* SHORT DATA */
  850. X    case DATA:                /* LONG DATA */
  851. X        gsctrl(fd,RJ|RFLD(rval));        /* not now please */
  852. X    case RJ:                               /* REJECT */
  853. X    case RR:                               /* RECEIVER READY */
  854. X        if (RVAL(inpk->c) == sval) {    /* check their R value */
  855. X        sval = (sval+1)&07;        /* update our S value */
  856. X        return;
  857. X        }
  858. X    case FAIL:                /* bad packet received */
  859. X    case TIME:                /* no packet received */
  860. X        gsdata(fd,pk,SFLD(sval)|RFLD(rval));/* send data packet again */
  861. X        numtry++;                /* but not forever */
  862. X        break;
  863. X    case CLOSE:
  864. X        gfail();                /* surprise! */
  865. X        /* NOTREACHED */
  866. X    }
  867. X    }
  868. X    gfail();                        /* too may retries, abort */
  869. X    /* NOTREACHED */
  870. X}
  871. X
  872. X/* grproto - take one packet from input queue */
  873. X
  874. XPacket *grproto(fd)
  875. Xint fd;
  876. X{
  877. X    int numtry = 0;                /* retry count */
  878. X    int xpct = (rval+1)&07;            /* expected sequence nr */
  879. X    register Packet *pk = inpk;            /* take one from the "pool" */
  880. X
  881. X    pk->k = ourseg;                /* initialize receive packet */
  882. X    pk->len = ourlen;
  883. X
  884. X    while (numtry < MAXTRY) {            /* don't loop forever */
  885. X    switch (grpack(fd,pk)) {        /* see what we got */
  886. X    case DATA:                /* LONG DATA */
  887. X    case SHORT:                /* SHORT DATA */
  888. X        if (SVAL(pk->c) == xpct) {        /* you're the 1 that I want */
  889. X        gsctrl(fd,RR|RFLD(rval = xpct));/* update R and acknowledge */
  890. X        return(pk);            /* we are done here */
  891. X        }                    /* else ignore the packet */
  892. X    case FAIL:                /* bad packet */
  893. X        gsctrl(fd,RJ|RFLD(rval));        /* reset their S value */
  894. X    case TIME:                /* no packet, no nak */
  895. X        numtry++;                /* don't loop forever */
  896. X        break;                /* read another packet */
  897. X    case RR:                /* RECEIVER READY */
  898. X    case RJ:                /* REJECT */
  899. X        break;                /* ignore */
  900. X    case CLOSE:                /* surprise! */
  901. X        gfail();                /* boy, am I confused */
  902. X        /* NOTREACHED */
  903. X    }
  904. X    }
  905. X    gfail();                        /* too may retries, abort */
  906. X    /* NOTREACHED */
  907. X}
  908. X
  909. X/*
  910. X* "The CLOSE message is used to terminate communications. Software on"
  911. X* "either or both ends of the communication channel may initiate"
  912. X* "termination. In any case when one end wants to terminate it sends"
  913. X* "CLOSE messages until one is received from the other end or until a"
  914. X* "programmable limit on the number of CLOSE messages is reached. Receipt"
  915. X* "of a CLOSE message causes a CLOSE message to be sent."
  916. X*
  917. X* Normally systems decide together when to turn off the protocol so
  918. X* that each system will start sending CLOSE messages at the same time.
  919. X*
  920. X* When a CLOSE message is received in the middle of a conversation
  921. X* a protocol error is generated in grproto() or gsproto(). Then
  922. X* gfinit() is called, so that the other system still sees a few CLOSE
  923. X* messages.
  924. X*/
  925. X
  926. X/* gfinit - shut down the g protocol */
  927. X
  928. Xint gfinit(fd)
  929. Xint fd;
  930. X{
  931. X    register int numtry;
  932. X
  933. X    for (numtry = 0; numtry < MAXTRY; numtry++) {    /* programmable limit */
  934. X    gsctrl(fd,CLOSE);                /* send CLOSE message */
  935. X    if (grpack(fd,inpk) == CLOSE)            /* hope for same */
  936. X        return(0);                    /* got it */
  937. X    }
  938. X    return(FAIL);                    /* no CLOSE received */
  939. X}
  940. END_OF_gtrans.c
  941. if test 10263 -ne `wc -c <gtrans.c`; then
  942.     echo shar: \"gtrans.c\" unpacked with wrong size!
  943. fi
  944. # end of overwriting check
  945. fi
  946. if test -f kbdinp.c -a "${1}" != "-c" ; then 
  947.   echo shar: Will not over-write existing file \"kbdinp.c\"
  948. else
  949. echo shar: Extracting \"kbdinp.c\" \(12538 characters\)
  950. sed "s/^X//" >kbdinp.c <<'END_OF_kbdinp.c'
  951. X/*++
  952. X/* NAME
  953. X/*    kbdinp 3
  954. X/* SUMMARY
  955. X/*    keyboard interpreter
  956. X/* PROJECT
  957. X/*    pc-mail
  958. X/* PACKAGE
  959. X/*    mailsh
  960. X/* SYNOPSIS
  961. X/*    void kbdinp(screen)
  962. X/*    Screen *screen;
  963. X/*
  964. X/*    void kbdinit()
  965. X/*    void kbdrest()
  966. X/* DESCRIPTION
  967. X/*    The keyboard interpreter is the machine that executes the program
  968. X/*    that is recorded in the form of Screen data structures.
  969. X/*    Its task is to interpret keyboard input and to
  970. X/*    invoke the appropriate action functions.
  971. X/*
  972. X/*    Depending on the return value of an action function
  973. X/*    the keyboard interpreter i) returns (S_BREAK), ii) repaints the 
  974. X/*    screen (S_REDRAW), or iii) just waits for more keyboard 
  975. X/*    input. Error handling is entirely up to the action functions.
  976. X/*
  977. X/*    The routines in this module are responsible for what appears in the
  978. X/*    top (function-key labels) and bottom sections (command dialogue)
  979. X/*    of the tty screen.
  980. X/*
  981. X/*    The middle screen section is handled by the pager (except when 
  982. X/*    help info is displayed).
  983. X/*
  984. X/*    kbdinit() sets the tty driver and keypad modes (no echo,
  985. X/*    punctual input).
  986. X/*    kbrest() restores the modes to what they were before the
  987. X/*    program was entered.
  988. X/*
  989. X/*    Terminal-specific codes for function keys and keypad are borrowed 
  990. X/*    from window.c.
  991. X/* FUNCTIONS AND MACROS
  992. X/*    printcl(), printat(), putw(), printw(), beep(), winout()
  993. X/* SEE ALSO
  994. X/*    window(3)       window management routines, function key codes
  995. X/*    window(5)       window definitions
  996. X/*    screen(3)       command key tables for each screen
  997. X/*    screen(5)       structure of command key tables
  998. X/* DIAGNOSTICS
  999. X/*    It beeps when an illegal key is pressed. Otherwise, no error
  1000. X/*    handling at all.
  1001. X/* AUTHOR(S)
  1002. X/*    W.Z. Venema
  1003. X/*    Eindhoven University of Technology
  1004. X/*    Department of Mathematics and Computer Science
  1005. X/*    Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  1006. X/* CREATION DATE
  1007. X/*    Thu Apr  2 18:43:12 GMT+1:00 1987
  1008. X/* LAST MODIFICATION
  1009. X/*    Mon Apr  4 23:42:29 MET 1988
  1010. X/* VERSION/RELEASE
  1011. X/*    1.3
  1012. X/*--*/
  1013. X
  1014. X#include <signal.h>
  1015. X#include <ctype.h>
  1016. X#include "defs.h"
  1017. X#include "mailsh.h"
  1018. X#include "screen.h"
  1019. X#include "window.h"
  1020. X
  1021. X#ifdef  unix
  1022. X#   if (SIII||SYSV)                /* AT&T */
  1023. X#    include <termio.h>
  1024. X    struct termio oldmode;
  1025. X#   else                                        /* V7 or Berkeley */
  1026. X#    include <sgtty.h>
  1027. X    struct sgttyb oldmode;
  1028. X#   endif
  1029. X#endif
  1030. X
  1031. X#define QUEST   "? "                /* prompt for input */
  1032. X#define STRLEN  ((wsize[BOT]-1)*CO-sizeof(QUEST)-2) /* max. input length */
  1033. X
  1034. Xhidden void kb_help(),kb_pause();        /* forward declarations */
  1035. Xhidden int kb_paint();
  1036. Xhidden int kb_str(),kb_key(),kb_cr();
  1037. Xhidden int input(),isempty();            /* forward declarations */
  1038. X
  1039. Xhidden char sect[] = "===============================================================================";
  1040. X
  1041. X/* kbdinp - recursively interpret screen descriptions */
  1042. X
  1043. Xpublic int kbdinp(screen)
  1044. XScreen *screen;
  1045. X{
  1046. X    kb_paint(screen);
  1047. X
  1048. X    if (iskey(screen->key))
  1049. X    return(kb_key(screen));            /* single-key commands */
  1050. X    else if (screen->key == STRING)
  1051. X    return(kb_str(screen));            /* string input screen */
  1052. X    else if (screen->key == ESCCR)
  1053. X    return(kb_cr(screen));            /* confirm/cancel screen */
  1054. X    else
  1055. X    fatal("kbdinp");            /* unexpected screen type */
  1056. X    /* NOTREACHED */
  1057. X}
  1058. X
  1059. X/* kb_paint - paint the screen (clean up this function) */
  1060. X
  1061. Xhidden int kb_paint(p)
  1062. Xregister Screen *p;
  1063. X{
  1064. X    char topline[BUFSIZ];            /* key label line */
  1065. X    register int k;                /* loop control variable */
  1066. X    int stat;                    /* status from mid window */
  1067. X    int promptloc;                /* where prompt "?" goes */
  1068. X
  1069. X    /*
  1070. X    * The top section of the screen consists of one line with
  1071. X    * key labels (in case of single-key input screen) and a
  1072. X    * bar that separates this section from the middle screen section.
  1073. X    *
  1074. X    * We always add a Help and ? label. The keyboard interpreter
  1075. X    * preempts the H and ? characters.
  1076. X    */
  1077. X
  1078. X    for (topline[0] = 0; p->key; p++) {        /* start top window */
  1079. X    if (iskey(p->key)) {            /* keystroke input ? */
  1080. X        strcat(topline,p->name);        /* append key label */
  1081. X        strcat(topline,"  ");        /* and some blanks */
  1082. X    } else if (topline[0]) {        /* leak if first entry */
  1083. X        fatal("mixed single-key and string input");
  1084. X    }
  1085. X    }
  1086. X    printcl(TOP,0,topline);            /* display key labels */
  1087. X    if (topline[0])                /* if there are labels */
  1088. X    printw("Help  ?");            /* display help key label too */
  1089. X    printcl(TOP,1,sect);            /* finish top window with bar */
  1090. X
  1091. X    /*
  1092. X    * The bottom section of the screen consists of a bar that separates
  1093. X    * us from the middle section, followed by the "help" string in
  1094. X    * the last entry of the current screen definition, followed by
  1095. X    * (if not a single-key input screen) a prompting question mark.
  1096. X    *
  1097. X    * We display the middle window after doing most of the bottom 
  1098. X    * section, so that the cursor can stay in the middle window in
  1099. X    * case of single-key input screens.
  1100. X    *
  1101. X    * We display the prompt (no single-key input screens) in the
  1102. X    * bottom section after doing the middle screen section, so that 
  1103. X    * the cursor can stay together with the prompt.
  1104. X    */
  1105. X
  1106. X    printcl(BOT,0,sect);            /* start lower window */
  1107. X    promptloc = printcl(BOT,1,p->help ? p->help : "")+1; /* general info */
  1108. X    for (k = promptloc; k < wsize[BOT]; k++)     /* clear rest of lower window */
  1109. X    printcl(BOT,k,"");            /* lower window done */
  1110. X
  1111. X    if (p->action)                /* fill middle window */
  1112. X    stat = CALL(p->action)();        /* middle window done */
  1113. X
  1114. X    if (topline[0] == '\0')            /* single-key screen? */
  1115. X    printat(BOT,promptloc,QUEST);        /* output "?" prompt */
  1116. X
  1117. X    return(stat);                /* from middle window filler */
  1118. X}
  1119. X
  1120. X/* kb_str - handle string input */
  1121. X
  1122. Xhidden int kb_str(p)
  1123. Xregister Screen *p;
  1124. X{
  1125. X    char string[BUFSIZ];            /* a character buffer */
  1126. X    register char *cp = string;            /* a character pointer */
  1127. X    register int c;                /* a character */
  1128. X    register int stat;
  1129. X
  1130. X    for (;;) {
  1131. X    if (!isascii(c = input())) {        /* ignore non-ascii codes */
  1132. X        beep();                /* complain */
  1133. X    } else if (c == ESC) {            /* ESC means don't do it */
  1134. X        printw(" (ESC)");            /* confirm input */
  1135. X        return(0);                /* nothing left here to do */
  1136. X    } else if ((c == ' ' || isprint(c)) && cp-string < STRLEN) {
  1137. X        putw(*cp++ = c);            /* accept/echo the character */
  1138. X    } else if (cp > string && (c == BS || c == DEL)) {/* delete character */
  1139. X        cp--;                /* remove char from buffer */
  1140. X        printw("\b \b");            /* remove char from screen */
  1141. X    } else if (c != ENTER || (*cp = 0,isempty(string))) {
  1142. X        beep();                /* complain */
  1143. X    } else if (putw(c),((stat = CALL(p->action)(string)) & S_BREAK)) {
  1144. X        return(stat);            /* we're done here */
  1145. X    } else if (stat & S_REDRAW) {        /* screen was changed */
  1146. X        kb_paint(p);            /* restore display */
  1147. X    }
  1148. X    }
  1149. X}
  1150. X
  1151. X/* kb_key - handle single-key input */
  1152. X
  1153. Xhidden int kb_key(p)
  1154. XScreen *p;
  1155. X{
  1156. X    register int c;                /* a character */
  1157. X    register Screen *q;                /* a screen (eh?) */
  1158. X    register int stat;                /* a status */
  1159. X
  1160. X    for (;;) {
  1161. X    if ((c = getkey()) == '?' || c == 'H') {/* is it a help request */
  1162. X        kb_help(p);                /* yes, display key info */
  1163. X        continue;                /* skip rest of loop */
  1164. X    }
  1165. X    for (q = p; q->key && q->key != c; q++)    /* look key up in table */
  1166. X        /* void */;
  1167. X    if (q->key == 0) {            /* unrecognized key */
  1168. X        beep();                /* complain */
  1169. X        continue;                /* skip rest of loop */
  1170. X    } else if (q->action == 0) {        /* action-less key */
  1171. X        return(0);                /* we are done here */
  1172. X    } else if ((stat = CALL(q->action)()) & S_BREAK) {/* action key */
  1173. X        return(stat);            /* we are done here */
  1174. X    } else if (stat & S_REDRAW) {        /* screen was changed */
  1175. X        kb_paint(p);            /* restore screen */
  1176. X    }
  1177. X    }
  1178. X}
  1179. X
  1180. X/* kb_cr - handle escape/enter input */
  1181. X
  1182. Xhidden int kb_cr(p)
  1183. XScreen *p;
  1184. X{
  1185. X    register int c;
  1186. X
  1187. X    for (;;) {
  1188. X    if ((c = input()) == ESC) {        /* don't do it */
  1189. X        printw(" (ESC)");            /* confirm input */
  1190. X        return(0);                /* we are done */
  1191. X    } else if (c == ENTER) {        /* do the action */
  1192. X        register int stat = CALL(p->action)();
  1193. X        if (stat & S_BREAK) {        /* child kills parent */
  1194. X        return(stat);            /* we are done */
  1195. X        } else if (stat & S_REDRAW) {    /* screen was changed */
  1196. X        kb_paint(p);            /* restore screen */
  1197. X        }
  1198. X    } else {                /* unacceptable input */
  1199. X        beep();                /* complain */
  1200. X    }
  1201. X    }
  1202. X}
  1203. X
  1204. X/* kb_help - display per-key help info; redraw screen when done */
  1205. X
  1206. Xhidden void kb_help(p)
  1207. Xregister Screen *p;
  1208. X{
  1209. X    static char any[] = "Press any key to continue";
  1210. X    register int k;
  1211. X
  1212. X    for (k = 0; k < wsize[MID]; k++)        /* erase middle window */
  1213. X    printcl(MID,k,"");
  1214. X    for (k = 0; p[k].key; k++)            /* display key info */
  1215. X    printcl(MID,k+1,strcons("   %-10s %s",p[k].name,p[k].help));
  1216. X    for (k = 1; k < wsize[BOT]-1; k++)        /* erase bottom window */
  1217. X    printcl(BOT,k,"");
  1218. X    printcl(BOT,1,any);                /* press any key to continue */
  1219. X    getkey();
  1220. X    kb_paint(p);                /* redraw screen */
  1221. X}
  1222. X
  1223. X/* structure that associates token value with function-key strings */
  1224. X
  1225. Xtypedef struct {
  1226. X    int token;                    /* key value */
  1227. X    char **seq;                    /* key string */
  1228. X} Key;
  1229. X
  1230. Xhidden Key kv[] = {
  1231. X    UP,     &KU,                /* key strings are set */
  1232. X    DOWN,   &KD,                /* in window.c */
  1233. X    LEFT,   &KL,
  1234. X    RIGHT,  &KR,
  1235. X    PGUP,   &PU,
  1236. X    PGDN,   &PD,
  1237. X    0,      0,
  1238. X};
  1239. X
  1240. X/* getkey - get key stroke, detect function keys, ignore case otherwise */
  1241. X
  1242. Xhidden int getkey()
  1243. X{
  1244. X    register int c;
  1245. X    register Key *kp;
  1246. X    char kstr[BUFSIZ];
  1247. X
  1248. X    /* 
  1249. X    * We assume that all function keys produce strings that start with 
  1250. X    * the same character, and that those strings all have the same 
  1251. X    * length. This is a reasonable assumption for cursor-control keys.
  1252. X    */
  1253. X
  1254. X    if ((c = input()) == *(kv[0].seq)[0]) {    /* lead-in char */
  1255. X    register int lvl;
  1256. X    for (lvl = 1; lvl < strlen(*(kv[0].seq)); lvl++)
  1257. X        kstr[lvl] = c = input();        /* read characters first */
  1258. X    kstr[lvl] = '\0';
  1259. X    for (kp = kv; kp->token; kp++)        /* then compare with strings */
  1260. X        if (strcmp(*(kp->seq)+1,kstr+1) == 0)
  1261. X        return(kp->token);        /* return token value */
  1262. X    }
  1263. X    return(islower(c) ? toupper(c) : c);    /* return last character */
  1264. X}
  1265. X
  1266. X/* input - read one character without echoing or waiting for carriage return */
  1267. X
  1268. Xhidden int input()
  1269. X{
  1270. X    /*
  1271. X    * On unix systems, the terminal driver has been instructed to
  1272. X    * not echo and to return one character as soon as it comes available. 
  1273. X    * Also the stdio routines have been instructed to work in an unbuffered 
  1274. X    * fashion. See kbdinit().
  1275. X    */
  1276. X
  1277. X#ifdef    unix
  1278. X    return(getchar());
  1279. X#endif
  1280. X
  1281. X    /*
  1282. X    * On IBM-PC machines a function key produces a null character
  1283. X    * followed by a scan code. We translate the null prefix to
  1284. X    * an escape character since that is more like normal terminals do.
  1285. X    * The trick is to find out when we read a null character whether it 
  1286. X    * was produced by pressing a real function-key or by pressing ctrl-@.
  1287. X    */
  1288. X
  1289. X#ifdef    MSDOS
  1290. X    register int c;
  1291. X    return((c = getch()) ? c : kbhit() ? ESC : 0);
  1292. X#endif
  1293. X}
  1294. X
  1295. X/* kbdinit - set input mode, turn keypad on */
  1296. X
  1297. Xpublic void kbdinit()
  1298. X{
  1299. X    /*
  1300. X    * On unix systems, instruct the terminal driver to not echo
  1301. X    * terminal input, and to return from a read as soon as one
  1302. X    * character comes available.
  1303. X    */
  1304. X
  1305. X#ifdef  unix
  1306. X# if (SIII||SYSV)
  1307. X    struct termio newmode;            /* AT&T */
  1308. X
  1309. X    ioctl(0,TCGETA,&oldmode);            /* save terminal mode */
  1310. X    ioctl(0,TCGETA,&newmode);            /* get terminal mode */
  1311. X    newmode.c_iflag &= ~(INLCR|ICRNL|IUCLC|BRKINT);
  1312. X    newmode.c_oflag &= ~OPOST;
  1313. X    newmode.c_lflag &= ~(ICANON|ISIG|ECHO);
  1314. X    newmode.c_cc[4] = 1;            /* do single-character reads */
  1315. X    ioctl(0,TCSETAF,&newmode);            /* set terminal mode */
  1316. X# else
  1317. X    struct sgttyb newmode;            /* V7 or Berkeley */
  1318. X
  1319. X    gtty(0,&oldmode);                /* save terminal mode */
  1320. X    gtty(0,&newmode);                /* get terminal mode */
  1321. X    newmode.sg_flags |= RAW;            /* don't wait for newline */
  1322. X    newmode.sg_flags &= ~(ECHO|CRMOD);        /* no echo, crlf mapping */
  1323. X    stty(0,&newmode);                /* set terminal mode */
  1324. X# endif
  1325. X#endif
  1326. X
  1327. X    signal(SIGINT,SIG_IGN);            /* ignore control-c */
  1328. X
  1329. X#ifdef    unix
  1330. X    setbuf(stdin,(char *) 0);            /* select unbuffered input */
  1331. X
  1332. X    if (KS && *KS)                /* if there is a keypad */
  1333. X    tputs(KS,1,fputchar);            /* enable it */
  1334. X#endif
  1335. X}
  1336. X
  1337. X/* kbdrest - reset terminal driver to previous state, turn keypad off */
  1338. X
  1339. Xpublic void kbdrest()
  1340. X{
  1341. X#ifdef  unix
  1342. X# if (SIII||SYSV)                /* AT&T */
  1343. X    ioctl(0,TCSETAF,&oldmode);
  1344. X# else                        /* V7 or Berkeley */
  1345. X    stty(0,&oldmode);                /* restore terminal mode */
  1346. X# endif
  1347. X
  1348. X    if (KE && *KE)                /* if there is a keypad */
  1349. X    tputs(KE,1,fputchar);            /* disable it */
  1350. X#endif
  1351. X}
  1352. X
  1353. X/* isempty - check a string is all blanks or empty */
  1354. X
  1355. Xhidden int isempty(s)
  1356. Xregister char *s;
  1357. X{
  1358. X    return(*s == 0 || (isspace(*s) && isempty(s+1)));
  1359. X}
  1360. END_OF_kbdinp.c
  1361. if test 12538 -ne `wc -c <kbdinp.c`; then
  1362.     echo shar: \"kbdinp.c\" unpacked with wrong size!
  1363. fi
  1364. # end of overwriting check
  1365. fi
  1366. if test -f kio.c -a "${1}" != "-c" ; then 
  1367.   echo shar: Will not over-write existing file \"kio.c\"
  1368. else
  1369. echo shar: Extracting \"kio.c\" \(4784 characters\)
  1370. sed "s/^X//" >kio.c <<'END_OF_kio.c'
  1371. X/*++
  1372. X/* NAME
  1373. X/*    kio 3
  1374. X/* SUMMARY
  1375. X/*    interface between uucico and k-protocol driver
  1376. X/* PACKAGE
  1377. X/*    uucp on the TUEnet
  1378. X/* SYNOPSIS
  1379. X/*    kturnon()
  1380. X/*
  1381. X/*    kwrmsg(type,str,fn)
  1382. X/*    char type, *str;
  1383. X/*    int fn;
  1384. X/*
  1385. X/*    krdmsg(str,fn)
  1386. X/*    char *str;
  1387. X/*    int fn;
  1388. X/*
  1389. X/*    krddata(fn,fp)
  1390. X/*    int fn;
  1391. X/*    FILE *fp;
  1392. X/*
  1393. X/*    kwrdata(fp,fn)
  1394. X/*    FILE *fp;
  1395. X/*    int fn;
  1396. X/*
  1397. X/*    kturnoff()
  1398. X/* IMPLICIT INPUTS
  1399. X/*    Ifn, Ofn, file descriptors
  1400. X/*    Debug, debugging level
  1401. X/* DESCRIPTION
  1402. X/*    The k protocol has been developed for the Sytek Localnet local area 
  1403. X/*    network at the Eindhoven University of Technology (THE).
  1404. X/*    Main features of this network are:
  1405. X/*
  1406. X/* .IP    o 
  1407. X/*    Network partners may talk at different baudrates. This implies
  1408. X/*    that the network does some buffering and that it needs flow control.
  1409. X/* .IP    o 
  1410. X/*    The network is normally not transparent for some control 
  1411. X/*    characters (XON,XOFF and locally-defined others), independent 
  1412. X/*    of the value of the eigth bit.
  1413. X/* .IP    o 
  1414. X/*    Some network stations are connected to telephone modems.
  1415. X/*
  1416. X/*    For these reasons, the k protocol must (i) rely on XON/XOFF flow 
  1417. X/*    control, (ii) be suitable for 7-bit data paths, (iii) avoid
  1418. X/*    sending of control characters and (iv) provide reliable operation
  1419. X/*    over dial-in and dial-out telephone lines.
  1420. X/*
  1421. X/*    Data are sent as checksummed 512-byte packets, terminated by an 
  1422. X/*    ASCII CR. Except for packet headers (^P), the k protocol only uses 
  1423. X/*    ASCII codes 040 through 0137. Three data bytes are expanded to four 
  1424. X/*    bytes upon transmission.
  1425. X/*    
  1426. X/*    The functions in kio.c form the interface between the uucico
  1427. X/*    controlling functions, and the k-protocol packet driver.
  1428. X/*
  1429. X/*    kturnon() sets the terminal line characteristics (XON/XOFF). Always
  1430. X/*    returns zero status.
  1431. X/*
  1432. X/*    krdmsg(), kwrmsg() exchange null-terminated strings.
  1433. X/*    Exit status zero, or FAIL.
  1434. X/*
  1435. X/*    krddata(), kwrdata() perform file i/o, and accounting. Exit status 
  1436. X/*    zero or FAIL.
  1437. X/*
  1438. X/*    kturnoff() sends a protocol abort sequence. Always returns zero 
  1439. X/*    status.
  1440. X/* FUNCTIONS AND MACROS
  1441. X/*    kread, kread, kwrite, kclose, k-protocol presentation layer 
  1442. X/* AUTHOR(S)
  1443. X/*    Wietse Venema
  1444. X/*    Eindhoven University of Technology
  1445. X/*    Department of Mathematics and Computer Science
  1446. X/*    Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  1447. X/* CREATION DATE
  1448. X/*    Mon Feb  3 10:13:34 MET 1986
  1449. X/* LAST MODIFICATION
  1450. X/*    Mon Apr  4 23:42:46 MET 1988
  1451. X/* VERSION/RELEASE
  1452. X/*    2.4
  1453. X/*--*/
  1454. X
  1455. X#include "uucp.h"
  1456. X
  1457. X#define    BUFLEN    BUFSIZ
  1458. X
  1459. Xkturnon()
  1460. X{
  1461. X    kopen(Ifn);
  1462. X    return 0;
  1463. X}
  1464. X
  1465. X
  1466. Xkturnoff()
  1467. X{
  1468. X    kclose(Ofn);
  1469. X    return 0;
  1470. X}
  1471. X
  1472. X
  1473. Xkwrmsg(type,str,fn)
  1474. Xchar type,*str;
  1475. Xint fn;
  1476. X{
  1477. X    char bufr[BUFSIZ],*s;
  1478. X
  1479. X    bufr[0] = type;
  1480. X    s = &bufr[1];
  1481. X    while (*str)
  1482. X    *s++ = *str++;
  1483. X    *s = '\0';
  1484. X    if (*(--s) == '\n')
  1485. X    *s = '\0';
  1486. X    DEBUG(6," kwrmsg: \"%s\"\n",bufr);
  1487. X
  1488. X    return (kwrite(fn,bufr,strlen(bufr)+1) > 0 ? 0 : FAIL);
  1489. X}
  1490. X
  1491. X
  1492. Xkrdmsg(str,fn)
  1493. Xchar *str;
  1494. Xint fn;
  1495. X{
  1496. X    int len;
  1497. X
  1498. X    for (;;) {
  1499. X    if ((len = kread(fn,str,BUFSIZ)) == 0) {
  1500. X        continue;
  1501. X    } else if (len > 0) {
  1502. X        str[len] = 0;
  1503. X        DEBUG(6," krdmsg: \"%s\"\n",str);
  1504. X        str += len;
  1505. X        if (str[-1] == '\0')
  1506. X        return 0;
  1507. X    } else {
  1508. X        return FAIL;
  1509. X    }
  1510. X    }
  1511. X}
  1512. X
  1513. X
  1514. Xkwrdata(fp1,fn)
  1515. XFILE *fp1;
  1516. X{
  1517. X    char bufr[BUFLEN];
  1518. X    int len;
  1519. X    int ret;
  1520. X    time_t t1,t2;
  1521. X    long bytes;
  1522. X    char text[BUFSIZ];
  1523. X
  1524. X    ret = FAIL;
  1525. X    bytes = 0L;
  1526. X    time(&t1);
  1527. X    while ((len = fread(bufr,sizeof (char),BUFLEN,fp1)) > 0) {
  1528. X    bytes += len;
  1529. X    if (kwrblk(bufr,len,fn) != len)
  1530. X        goto acct;
  1531. X    if (len != BUFLEN)
  1532. X        break;
  1533. X    }
  1534. X    ret = kwrblk(bufr,0,fn);
  1535. Xacct:
  1536. X    time(&t2);
  1537. X    sprintf(text,ret == 0 ?
  1538. X    "sent data %ld bytes %ld secs" :
  1539. X    "send failed after %ld bytes",
  1540. X    bytes,t2 - t1);
  1541. X    DEBUG(1,"%s\n",text);
  1542. X    syslog(text);
  1543. X    sysacct(bytes,t2 - t1);
  1544. X    if (ret)
  1545. X    sysaccf(NULL);        /* force accounting */
  1546. X    return ret;
  1547. X}
  1548. X
  1549. X
  1550. Xkrddata(fn,fp2)
  1551. XFILE *fp2;
  1552. X{
  1553. X    int len,ret;
  1554. X    char bufr[BUFLEN];
  1555. X    time_t t1,t2;
  1556. X    long bytes;
  1557. X    char text[BUFSIZ];
  1558. X
  1559. X    ret = FAIL;
  1560. X    bytes = 0L;
  1561. X    time(&t1);
  1562. X    for (;;) {
  1563. X    len = krdblk(bufr,BUFLEN,fn);
  1564. X    if (len < 0)
  1565. X        goto acct;
  1566. X    bytes += len;
  1567. X    if (fwrite(bufr,sizeof (char),len,fp2) != len)
  1568. X        goto acct;
  1569. X    if (len < BUFLEN)
  1570. X        break;
  1571. X    }
  1572. X    ret = 0;
  1573. Xacct:
  1574. X    time(&t2);
  1575. X    sprintf(text,ret == 0 ? 
  1576. X    "received data %ld bytes %ld secs" :
  1577. X    "receive failed after %ld bytes",
  1578. X    bytes,t2 - t1);
  1579. X    DEBUG(1,"%s\n",text);
  1580. X    syslog(text);
  1581. X    sysacct(bytes,t2 - t1);
  1582. X    if (ret)
  1583. X    sysaccf(NULL);        /* force accounting */
  1584. X    return ret;
  1585. X}
  1586. X
  1587. X
  1588. Xkrdblk(blk,len, fn)
  1589. Xchar *blk;
  1590. Xint len,fn;
  1591. X{
  1592. X    int i,ret;
  1593. X
  1594. X    for (i = 0; i < len; i += ret) {
  1595. X    if ((ret = kread(fn,blk,len-i)) == 0) {
  1596. X        break;
  1597. X    } else if (ret > 0) {
  1598. X        blk += ret;
  1599. X    } else {
  1600. X        return FAIL;
  1601. X    }
  1602. X    }
  1603. X    return i;
  1604. X}
  1605. X
  1606. X
  1607. Xkwrblk(blk,len,fn)
  1608. Xchar *blk;
  1609. Xint len,fn;
  1610. X{
  1611. X    return kwrite(fn,blk,len);
  1612. X}
  1613. END_OF_kio.c
  1614. if test 4784 -ne `wc -c <kio.c`; then
  1615.     echo shar: \"kio.c\" unpacked with wrong size!
  1616. fi
  1617. # end of overwriting check
  1618. fi
  1619. if test -f window.c -a "${1}" != "-c" ; then 
  1620.   echo shar: Will not over-write existing file \"window.c\"
  1621. else
  1622. echo shar: Extracting \"window.c\" \(9885 characters\)
  1623. sed "s/^X//" >window.c <<'END_OF_window.c'
  1624. X/*++
  1625. X/* NAME
  1626. X/*      window 3
  1627. X/* SUMMARY
  1628. X/*      screen manager
  1629. X/* PROJECT
  1630. X/*      pc-mail
  1631. X/* PACKAGE
  1632. X/*      mailsh
  1633. X/* SYNOPSIS
  1634. X/*      #include "window.h"
  1635. X/*
  1636. X/*      int printcl(window,line,s)
  1637. X/*      int window;
  1638. X/*      int line;
  1639. X/*      char *s;
  1640. X/*
  1641. X/*      int printat(window,line,s)
  1642. X/*      int window;
  1643. X/*      int line;
  1644. X/*      char *s;
  1645. X/*
  1646. X/*      int putw(c)
  1647. X/*      int c;
  1648. X/*
  1649. X/*      int printw(s)
  1650. X/*      char *s;
  1651. X/*
  1652. X/*      void clrtoeol()
  1653. X/*
  1654. X/*      void clrtobot()
  1655. X/*
  1656. X/*      void clrscreen()
  1657. X/*
  1658. X/*      void beep()
  1659. X/*
  1660. X/*    int fputchar(c)
  1661. X/*    int c;
  1662. X/*
  1663. X/*      void wininit()          /* extract terminal control from database */
  1664. X/* DESCRIPTION
  1665. X/*      The window manipulator is responsable for three screen windows:
  1666. X/*      the top window for key labels, the middle window for 
  1667. X/*      information, and the lower window for messages and dialogue.
  1668. X/*      Use is made of the terminal capability database termcap.
  1669. X/*
  1670. X/*    For MS-DOS systems, there is a termcap facility that generates
  1671. X/*    escape sequences for the ANSI.SYS terminal driver.
  1672. X/*
  1673. X/*      Appropriate macros for window selection are given in window.h.
  1674. X/*      Needless to say, all screen output should proceed through 
  1675. X/*      functions in this module.
  1676. X/*
  1677. X/*      All character output functions return the number of screen lines
  1678. X/*      used for outputting the text (at least 1).
  1679. X/*
  1680. X/*      printat() writes the specified line in the specified window,
  1681. X/*      starting at the left margin. 
  1682. X/*
  1683. X/*      printcl() performs the same functions as printat() and erases to
  1684. X/*      the end of the line. 
  1685. X/*
  1686. X/*      printw() writes a character string to the current cursor location.
  1687. X/*      putw() does the same for characters. These two functions are
  1688. X/*      mostly used for output to the top and bottom windows.
  1689. X/*
  1690. X/*      cltroeol(), clrtobot() erase the screen from the cursor to the
  1691. X/*      end of the line and screen respectively. beep() makes some noise.
  1692. X/*
  1693. X/*    fputchar() outputs a character to stdout, just as putchar,
  1694. X/*    but it is not a macro.
  1695. X/*
  1696. X/*      wininit() initializes the window manipulator. It reads the
  1697. X/*    terminal capabilities from the termcap database.
  1698. X/* FILES
  1699. X/*      /etc/termcap, $TERMCAP         on V7 or BSD UNIX
  1700. X/*    /usr/lib/terminfo, $TERMINFO    on System-V UNIX
  1701. X/* SEE ALSO
  1702. X/*      window(5)       window manager definitions
  1703. X/* DIAGNOSTICS
  1704. X/*      The program is terminated with an error message if no terminal
  1705. X/*      descriptions could be found, if the terminal lacks some
  1706. X/*      essential features or if an attempt is made to write outside
  1707. X/*      a window.
  1708. X/* BUGS
  1709. X/*    This module is a big mess. It should be replaced by a PD
  1710. X/*    curses/termcap library.
  1711. X/* AUTHOR(S)
  1712. X/*      W.Z. Venema
  1713. X/*      Eindhoven University of Technology
  1714. X/*      Department of Mathematics and Computer Science
  1715. X/*      Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  1716. X/* CREATION DATE
  1717. X/*      Wed Apr  1 21:14:53 GMT+1:00 1987
  1718. X/* LAST MODIFICATION
  1719. X/*    Mon Apr  4 23:51:29 MET 1988
  1720. X/* VERSION/RELEASE
  1721. X/*    1.3
  1722. X/*--*/
  1723. X
  1724. X#include <ctype.h>
  1725. X#include "defs.h"
  1726. X#include "window.h"
  1727. X
  1728. X#define BUFFERSIZE      1024            /* max. length of termcap entry */
  1729. X
  1730. Xhidden char outbuf[BUFSIZ];             /* for stdio */
  1731. X
  1732. Xhidden char tcapent[BUFFERSIZE];        /* storage for termcap entry */
  1733. Xhidden char capst[BUFFERSIZE];          /* storage for tgetstr */
  1734. Xhidden char *capptr = capst;            /* pointer to next tgetstr output */
  1735. X
  1736. Xextern char *tgetstr();                 /* returns capability string */
  1737. Xextern char *getenv();
  1738. Xextern char *tgoto();                   /* returns cursor addressing code */
  1739. X
  1740. Xpublic char *KU,*KD,*KL,*KR,*PU,*PD;    /* function-key strings */
  1741. Xpublic char *KS,*KE;                    /* keypad enable/disable */
  1742. X
  1743. Xhidden char *CL,*CD,*CM,*CE,*SO,*SE;    /* screen capabilities */
  1744. Xpublic int CO,LI;                       /* screen size */
  1745. X
  1746. Xpublic int wbase[BOT+1];                /* where windows start */
  1747. Xpublic int wsize[BOT+1];                /* how big windows are */
  1748. X
  1749. Xhidden int curwin = 0;                  /* what window we are in */
  1750. Xhidden int curx = 0;                    /* where we are on the screen */
  1751. Xhidden int cury = 0;                    /* line in that window */
  1752. X
  1753. Xhidden void winout();
  1754. X
  1755. X/* printcl - print one line in a window, then clear to end of line */
  1756. X
  1757. Xpublic int printcl(window,line,s)
  1758. Xint window;
  1759. Xint line;
  1760. Xchar *s;
  1761. X{
  1762. X    if (line < 0 || line >= wsize[window])
  1763. X    fatal("line %d not in window %d",line,window);
  1764. X
  1765. X    tputs(tgoto(CM,curx = 0,(cury = line)+wbase[curwin = window]),1,fputchar);
  1766. X    winout(s);
  1767. X    if (cury < wsize[curwin])
  1768. X    tputs(CE,1,fputchar);
  1769. X    fflush(stdout);
  1770. X    return(cury-line+1);
  1771. X}
  1772. X
  1773. X/* printat - print one line in a window */
  1774. X
  1775. Xpublic int printat(window,line,s)
  1776. Xint window;
  1777. Xint line;
  1778. Xchar *s;
  1779. X{
  1780. X    if (line < 0 || line >= wsize[window])
  1781. X    fatal("line %d not in window %d",line,window);
  1782. X
  1783. X    tputs(tgoto(CM,curx = 0,(cury = line)+wbase[curwin = window]),1,fputchar);
  1784. X    winout(s);
  1785. X    fflush(stdout);
  1786. X    return(cury-line+1);
  1787. X}
  1788. X
  1789. X/* putw - put character at current location */
  1790. X
  1791. Xpublic int putw(c)
  1792. Xint c;
  1793. X{
  1794. X    register int line = cury;
  1795. X    char buf[2];
  1796. X
  1797. X    buf[0] = c;
  1798. X    buf[1] = '\0';
  1799. X    winout(buf);
  1800. X    fflush(stdout);
  1801. X    return(cury-line+1);
  1802. X}
  1803. X
  1804. X/* printw - formatted print at current location */
  1805. X
  1806. Xpublic int printw(s)
  1807. Xchar *s;
  1808. X{
  1809. X    register int line = cury;
  1810. X
  1811. X    winout(s);
  1812. X    fflush(stdout);
  1813. X    return(cury-line+1);
  1814. X}
  1815. X
  1816. X/* winout - keep track of the column we are in (clean this up) */
  1817. X
  1818. X/*
  1819. X* Routine to check that output stays within its window.
  1820. X* It takes care of terminals that cannot wrap long lines
  1821. X* or cannot backspace across the beginning of a line.
  1822. X*/
  1823. X
  1824. Xhidden void winout(s)   /* implicit inputs/outputs: cury,curx,curwin,wsize */
  1825. Xregister char *s;
  1826. X{
  1827. X    register int ch;
  1828. X    int limit;
  1829. X
  1830. X    for (limit = wsize[curwin]; (ch = (*s&0177)) && cury < limit; s++) {
  1831. X    if (isprint(ch) || ch == ' ') {         /* if printable */
  1832. X        putchar(ch),curx++;                 /* leave it alone */
  1833. X    } else if (ch == '\t') {                /* if horizontal tab */
  1834. X        do {
  1835. X        winout(" ");                    /* expand it */
  1836. X        } while (curx&7 && cury < limit);
  1837. X    } else if (ch == '\b') {                /* backspace */
  1838. X        if (curx == 0 && cury == 0) {
  1839. X        /* void */ ;                    /* don't leave the window */
  1840. X        } else if ((curx = (curx > 0 ? curx-1 : (cury--,CO-1))) != CO-1) {
  1841. X        putchar(ch);                    /* not at start of line */
  1842. X        } else {
  1843. X        tputs(tgoto(CM,curx,cury+wbase[curwin]),1,fputchar);
  1844. X        }
  1845. X    } else if (ch == '\n') {        /* if newline */
  1846. X        tputs(CE,1,fputchar);        /* erase rest of line */
  1847. X        if ((curx = 0),++cury < limit)      /* advance virtual cursor */
  1848. X        fputs("\r\n",stdout);           /* advance physical cursor */
  1849. X    } else if (ch == '\r') {                /* if carriage return */
  1850. X        putchar(ch),curx = 0;               /* output it and reset curx */
  1851. X    } else if (ch == '\07') {               /* if the bell */
  1852. X        putchar(ch);                        /* make them sound */
  1853. X    } else {                                /* otherwise garbage */
  1854. X        char buf[3];
  1855. X        sprintf(buf,"^%c",ch^0100);         /* uncontrollify */
  1856. X        winout(buf);                        /* output it */
  1857. X    }
  1858. X    if (curx >= CO)                         /* at rhs of screen */
  1859. X        tputs(tgoto(CM,curx = 0,++cury+wbase[curwin]),1,fputchar);
  1860. X    }
  1861. X}
  1862. X
  1863. X#ifdef unix
  1864. X
  1865. X/* fputchar - output a character on stdout */
  1866. X
  1867. Xpublic int fputchar(c)
  1868. Xint c;
  1869. X{
  1870. X    return(putchar(c));
  1871. X}
  1872. X
  1873. X#endif /* unix */
  1874. X
  1875. X/* clrtoeol - clear to end of line */
  1876. X
  1877. Xpublic void clrtoeol()
  1878. X{
  1879. X    tputs(CE,1,fputchar);
  1880. X}
  1881. X
  1882. X/* clrtobot - clear to end of screen */
  1883. X
  1884. Xpublic void clrtobot()
  1885. X{
  1886. X    tputs(CD,1,fputchar);
  1887. X}
  1888. X
  1889. X/* clrscreen - clear screen */
  1890. X
  1891. Xpublic void clrscreen()
  1892. X{
  1893. X    tputs(CL,1,fputchar);
  1894. X}
  1895. X
  1896. X/* beep - ring the bell */
  1897. X
  1898. Xpublic void beep()
  1899. X{
  1900. X    putw('\07');
  1901. X}
  1902. X/* wininit - extract terminal info and initialize window manager */
  1903. X
  1904. Xpublic void wininit()
  1905. X{
  1906. X    char *term;
  1907. X
  1908. X    setbuf(stdout,outbuf);                      /* buffer stdout */
  1909. X
  1910. X    term = getenv("TERM");
  1911. X    switch(tgetent(tcapent,term = getenv("TERM"))) {
  1912. X    case -1:
  1913. X    fatal("termcap database not found\n");
  1914. X    /* NOTREACHED */
  1915. X    case 0:
  1916. X    fatal("unknown terminal: %s\n",term);
  1917. X    /* NOTREACHED */
  1918. X    }
  1919. X    /* extract capabilities. should use tables, but what the heck */
  1920. X
  1921. X    if ((CE = tgetstr("ce",&capptr)) == 0       /* clear to end of line */
  1922. X    || (CD = tgetstr("cd",&capptr)) == 0        /* clear to end of screen */
  1923. X    || (CL = tgetstr("cl",&capptr)) == 0        /* clear to end of screen */
  1924. X#ifdef  someday
  1925. X    || (SO = tgetstr("so",&capptr)) == 0        /* stand-out on */
  1926. X    || (SE = tgetstr("se",&capptr)) == 0        /* stand-out off */
  1927. X#endif
  1928. X    || (CM = tgetstr("cm",&capptr)) == 0        /* cursor movement */
  1929. X    || (KU = tgetstr("ku",&capptr)) == 0        /* up-arrow */
  1930. X    || (KD = tgetstr("kd",&capptr)) == 0        /* down_arrow */
  1931. X    || (KL = tgetstr("kl",&capptr)) == 0        /* left-arrow */
  1932. X    || (KR = tgetstr("kr",&capptr)) == 0        /* right-arrow */
  1933. X#ifdef  unix
  1934. X    || (PU = tgetstr("k1",&capptr)) == 0        /* page-up (F1) */
  1935. X    || (PD = tgetstr("k2",&capptr)) == 0        /* page down (F2) */
  1936. X#endif
  1937. X#ifdef  MSDOS
  1938. X    || (PU = tgetstr("PU",&capptr)) == 0        /* really PgUp */
  1939. X    || (PD = tgetstr("PD",&capptr)) == 0        /* really PgDn */
  1940. X#endif
  1941. X    || (CO = tgetnum("co")) == 0
  1942. X    || (LI = tgetnum("li")) == 0)
  1943. X    fatal("Your terminal is too dumb");
  1944. X
  1945. X    /* the following capabilities are not mandatory */
  1946. X
  1947. X    KS = tgetstr("ks",&capptr);                 /* keypad on */
  1948. X    KE = tgetstr("ke",&capptr);                 /* keypad off */
  1949. X
  1950. X    /* set window base and size */
  1951. X
  1952. X    if (CO < 80)
  1953. X    fatal("Terminal screen is to narrow");
  1954. X    wsize[TOP] = 2;
  1955. X    wbase[TOP] = 0;
  1956. X    wsize[BOT] = 5;
  1957. X    wbase[BOT] = LI-wsize[BOT];
  1958. X    wbase[MID] = wbase[TOP]+wsize[TOP];
  1959. X    if ((wsize[MID] = wbase[BOT]-wbase[MID]) < 5)
  1960. X    fatal("Not enough lines on this terminal");
  1961. X}
  1962. END_OF_window.c
  1963. if test 9885 -ne `wc -c <window.c`; then
  1964.     echo shar: \"window.c\" unpacked with wrong size!
  1965. fi
  1966. # end of overwriting check
  1967. fi
  1968. echo shar: End of archive 2 \(of 8\).
  1969. cp /dev/null ark2isdone
  1970. MISSING=""
  1971. for I in 1 2 3 4 5 6 7 8 ; do
  1972.     if test ! -f ark${I}isdone ; then
  1973.     MISSING="${MISSING} ${I}"
  1974.     fi
  1975. done
  1976. if test "${MISSING}" = "" ; then
  1977.     echo You have unpacked all 8 archives.
  1978.     rm -f ark[1-9]isdone
  1979. else
  1980.     echo You still need to unpack the following archives:
  1981.     echo "        " ${MISSING}
  1982. fi
  1983. ##  End of shell archive.
  1984. exit 0
  1985. -- 
  1986. uucp:    mcvax!eutrc3!wswietse    | Eindhoven University of Technology
  1987. bitnet:    wswietse@heithe5    | Dept. of Mathematics and Computer Science
  1988. surf:    tuerc5::wswietse    | Eindhoven, The Netherlands.
  1989.